package com.ebei.admin.common.util;

import com.ebei.admin.common.constant.Constants;
import com.ebei.admin.common.util.annotation.ExcelField;
import com.ebei.common.constant.CommonConstant;
import com.microsoft.schemas.office.visio.x2012.main.CellType;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.swing.filechooser.FileSystemView;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;

public final class DocUtil {

    /**
     * 拼装单个obj
     *
     * @param row
     * @return
     * @throws Exception
     */
    private static Map<String, Object> dataObj(Class<?> clazz, HSSFRow row) throws Exception {
        List<Field> fields = FieldUtils.getAllFieldsList(clazz);
        if (fields == null || fields.size() < 1) {
            return null;
        }

        //容器
        Map<String, Object> map = new HashMap<String, Object>();

        //注意excel表格字段顺序要和obj字段顺序对齐 （如果有多余字段请另作特殊下标对应处理）
        for (int j = 0; j < fields.size(); j++) {
            Field field = fields.get(j);
            row.cellIterator();
            if (Modifier.isStatic(field.getModifiers())) {
                field.setAccessible(true);  //将private设置为可访问
                map.put(field.getName(), field.get(clazz));
            } else {
                String value = getOrDefault(row.getCell(j), field);
                if (field.getName().equals("sex")) {
                    value = Constants.EXCEL_SEX_MAN.equals(value) ? Constants.MAN : Constants.WOMEN;
                }
                if (field.getName().equals("type")) {
                    value = Constants.EXCEL_TYPE_GOV.equals(value) ? Constants.TYPE_GOV : Constants.TYPE_COM;
                }
                map.put(field.getName(), value);
            }
        }
        return map;
    }

    public static List<Map<String, Object>> importExcel(MultipartFile file, Class<?> clazz) throws Exception {
        //装载流
        POIFSFileSystem fs = new POIFSFileSystem(file.getInputStream());
        HSSFWorkbook hw = new HSSFWorkbook(fs);

        //获取第一个sheet页
        HSSFSheet sheet = hw.getSheetAt(0);

        //容器
        List<Map<String, Object>> ret = new ArrayList<Map<String, Object>>();

        //遍历行 从下标第一行开始（去除标题,所以要+1）
        for (int i = 1; i < sheet.getLastRowNum() + 1; i++) {
            HSSFRow row = sheet.getRow(i);
            if (row != null) {
                //装载obj
                ret.add(dataObj(clazz, row));
            }
        }
        return ret;
    }

    /**
     * 处理val（暂时只处理string和number，可以自己添加自己需要的val类型）
     *
     * @param hssfCell
     * @return
     */
    public static String getOrDefault(HSSFCell hssfCell, Field field) {
        if (hssfCell == null) {   //如果为null,,打算返回默认值,但是现在返回空字符串
            //return "";
            return clazzDefaultValue(field.getType());
        } else {
            hssfCell.setCellType(HSSFCell.CELL_TYPE_STRING);
            return hssfCell.getStringCellValue();
        }
    }

    public static boolean isExcel(MultipartFile file) {
        return file.getOriginalFilename().endsWith(".xls");
    }

    /**
     * 在把Excel表格中的值读取到应用中的时候,,空白的值将会有默认值,而不会是null\
     * ,,根据类型来设定默认值
     *
     * @param clz
     * @return
     */
    private static String clazzDefaultValue(Class clz) {
        Map<Class, String> defaultValueMap = new HashMap<>();
        defaultValueMap.put(Date.class, CommonConstant.Y2S.format(new Date()));
        defaultValueMap.put(String.class, "");
        return defaultValueMap.get(clz);
    }

    private static String EXCEL_TEMPLATE_NAME = "Excel表格模版";

    public static void exportExcel(HttpServletResponse response, Class<?> clazz, String templateName) throws Exception {
        File desktopDir = FileSystemView.getFileSystemView().getHomeDirectory();
        String savePath = desktopDir.getAbsolutePath() + "\\";  //在桌面生成Excel模版
        List<Field> filedList = FieldUtils.getAllFieldsList(clazz);

        ArrayList<String> titleList = new ArrayList<String>();
        ArrayList<Integer> widthList = new ArrayList<Integer>();
        for (Field field : filedList) {
            //获取注解上的值,当做列名
            if (field.isAnnotationPresent(ExcelField.class)) {
                ExcelField excelField = (ExcelField) field.getAnnotation(ExcelField.class);
                widthList.add(excelField.width());
                titleList.add(excelField.value());
            }
        }

        //String[] excelHeader = { "用户编号", "姓名", "手机号码", "区域", "城市", "学校", "所属学生代表", "推荐人编号", "是否禁用", "加入时间"};
        String[] excelHeader = (String[]) titleList.toArray(new String[titleList.size()]);

        //int[] excelHeaderWidth = { 140, 80, 100, 80, 80, 100, 100, 140, 80, 90};
        Integer[] excelHeaderWidth = (Integer[]) widthList.toArray(new Integer[widthList.size()]);

        String fileName = templateName + CommonConstant.Y2D.format(new Date()) + ".xls";
        HSSFWorkbook wb = new HSSFWorkbook();
        HSSFSheet sheet = wb.createSheet("导出信息列表");
        //sheet.setAutobreaks(true);
        // 产生表格标题行
        HSSFRow row = sheet.createRow(0);
        HSSFFont font = wb.createFont();
        font.setColor(HSSFColor.BLUE.index);
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); // 粗体
        HSSFCellStyle styleHeader = wb.createCellStyle();
        styleHeader.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平居中
        styleHeader.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
        styleHeader.setFont(font);
        HSSFCellStyle styleBody = wb.createCellStyle();
        styleBody.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
        // 添加表格头，设置列宽度（像素）
        for (int i = 0; i < excelHeader.length; i++) {
            HSSFCell cell = row.createCell(i);
            row.setHeight((short) 600);
            cell.setCellValue(excelHeader[i]);
            cell.setCellStyle(styleHeader);
            sheet.setColumnWidth(i, 32 * excelHeaderWidth[i]);
        }

        try {
            File f = new File(savePath);
            if (!f.exists()) {
                f.mkdirs();
            }
            File file = new File(savePath, fileName);
            file.createNewFile();
            FileOutputStream fos = new FileOutputStream(file);
            wb.write(fos);
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //这里可稍做优化,根据文件类型动态设置此属性
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-Disposition", "attachment; filename=" + new String(fileName.getBytes("utf-8"), "iso8859-1") + ";");
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(new File(savePath + fileName)));
        ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
        byte[] buff = new byte[1024];
        int len = 0;
        while ((len = in.read(buff)) != -1) {
            out.write(buff, 0, len);
        }
        in.close();
        ServletOutputStream os = response.getOutputStream();
        os.write(out.toByteArray());
        os.flush();
        os.close();
        out.close();
    }

    /**
     * 根据file类型操作文件
     *
     * @param fileName
     * @return
     */
    public static boolean delete(String fileName) {
        File file = new File(fileName);
        if (!file.exists()) {
            System.out.println("删除文件失败:" + fileName + "不存在！");
            return false;
        } else {
            if (file.isFile())
                return deleteFile(fileName);
            else
                return deleteDirectory(fileName);
        }
    }

    /**
     * 删除单个文件
     *
     * @param fileName 要删除的文件的文件名
     * @return 单个文件删除成功返回true，否则返回false
     */
    public static boolean deleteFile(String fileName) {
        File file = new File(fileName);
        // 如果文件路径所对应的文件存在，并且是一个文件，则直接删除
        if (file.exists() && file.isFile()) {
            if (file.delete()) {
                System.out.println("删除单个文件" + fileName + "成功！");
                return true;
            } else {
                System.out.println("删除单个文件" + fileName + "失败！");
                return false;
            }
        } else {
            System.out.println("删除单个文件失败：" + fileName + "不存在！");
            return false;
        }
    }

    /**
     * 删除目录及目录下的文件
     *
     * @param dir 要删除的目录的文件路径
     * @return 目录删除成功返回true，否则返回false
     */
    public static boolean deleteDirectory(String dir) {
        // 如果dir不以文件分隔符结尾，自动添加文件分隔符
        if (!dir.endsWith(File.separator))
            dir = dir + File.separator;
        File dirFile = new File(dir);
        // 如果dir对应的文件不存在，或者不是一个目录，则退出
        if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
            System.out.println("删除目录失败：" + dir + "不存在！");
            return false;
        }
        boolean flag = true;
        // 删除文件夹中的所有文件包括子目录
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            // 删除子文件
            if (files[i].isFile()) {
                flag = deleteFile(files[i].getAbsolutePath());
                if (!flag)
                    break;
            }
            // 删除子目录
            else if (files[i].isDirectory()) {
                flag = deleteDirectory(files[i].getAbsolutePath());
                if (!flag)
                    break;
            }
        }
        if (!flag) {
            System.out.println("删除目录失败！");
            return false;
        }
        // 删除当前目录
        if (dirFile.delete()) {
            System.out.println("删除目录" + dir + "成功！");
            return true;
        } else {
            return false;
        }
    }

}
